package com.navidove.hibernatetool;

import java.beans.Introspector;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringUtils;
import org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy;
import org.hibernate.cfg.reveng.DelegatingReverseEngineeringStrategy;
import org.hibernate.cfg.reveng.ReverseEngineeringRuntimeInfo;
import org.hibernate.cfg.reveng.ReverseEngineeringSettings;
import org.hibernate.cfg.reveng.ReverseEngineeringStrategyUtil;
import org.hibernate.cfg.reveng.TableIdentifier;
import org.hibernate.mapping.Column;
import org.hibernate.util.StringHelper;

public class ReverseEngineeringStrategy extends DelegatingReverseEngineeringStrategy {
    
    private ReverseEngineeringSettings settings;
    
    private ReverseEngineeringRuntimeInfo runtimeInfo;
    
    public ReverseEngineeringStrategy() {
        super(new DefaultReverseEngineeringStrategy());
    }
    
    public ReverseEngineeringStrategy(org.hibernate.cfg.reveng.ReverseEngineeringStrategy reverseEngineeringStrategy) {
        super(reverseEngineeringStrategy);
    }

    public void setSettings(ReverseEngineeringSettings settings) {
        this.settings = settings; 
    }    
    
    /**
     * @see org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy#tableToClassName(org.hibernate.cfg.reveng.TableIdentifier)
     */
    public String tableToClassName(TableIdentifier tableIdentifier) {
        String val = tableIdentifier.getName();
        val = val.equals(val.toUpperCase()) ? val.toLowerCase(): val;
        
        String name = ".model.bo.";
        
        StringTokenizer tokenizer = new StringTokenizer(val, "_");
        while(tokenizer.hasMoreTokens()) {
        	name += StringUtils.capitalize(tokenizer.nextToken());
        }

        return settings.getDefaultPackageName()+name;
    }
    
    /**
     * @see org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy#columnToHibernateTypeName(org.hibernate.cfg.reveng.TableIdentifier, java.lang.String, int, int, int, int, boolean, boolean)
     */
    public String columnToHibernateTypeName(TableIdentifier table,
            String columnName, int sqlType, int length, int precision,
            int scale, boolean nullable, boolean generatedIdentifier) {
        
        return super.columnToHibernateTypeName(table, columnName, sqlType, length,
                precision, scale, true, generatedIdentifier);
    }

    @SuppressWarnings("rawtypes")
	public String foreignKeyToEntityName(String keyname,
            TableIdentifier fromTable, List fromColumnNames,
            TableIdentifier referencedTable, List referencedColumnNames,
            boolean uniqueReference) {

        String propertyName;
        if (!uniqueReference) {
            String name = ((Column) fromColumnNames.get(0)).getName();
            name=name.toLowerCase().replace("_id", "");
            String[] arrays = name.split("_");
            name ="";
            for (String s:arrays) {
                name=name+StringUtils.capitalize(s.toLowerCase());
            }
            
            propertyName = Introspector.decapitalize(name);
        } else {
            propertyName = Introspector.decapitalize(StringHelper
                    .unqualify(tableToClassName(referencedTable)));
        }
        return propertyName;
    }
    
    @SuppressWarnings("rawtypes")
	@Override
    public String foreignKeyToCollectionName(String keyname,
            TableIdentifier fromTable, List fromColumns,
            TableIdentifier referencedTable, List referencedColumns,
            boolean uniqueReference) {
        String propertyName = null;
        propertyName = Introspector.decapitalize(StringHelper.unqualify(tableToClassName(fromTable) ) );
        if(!uniqueReference) {
            String columnName = ( (Column) fromColumns.get(0) ).getName();
            propertyName = propertyName + "For" + ReverseEngineeringStrategyUtil.toUpperCamelCase(columnName);
        } else {
            
            propertyName=ReverseEngineeringStrategyUtil.simplePluralize(propertyName);
        }
        return propertyName;
    }
    
    @SuppressWarnings("rawtypes")
	@Override
    public List getPrimaryKeyColumnNames(TableIdentifier identifier) {
        if (runtimeInfo.getTable(identifier).getPrimaryKey()==null) {
            return Arrays.asList(new String[]{"id"});
        }
        return super.getPrimaryKeyColumnNames(identifier);
    }
    
    @Override
    public void configure(ReverseEngineeringRuntimeInfo runtimeInfo) {
        super.configure(runtimeInfo);
        this.runtimeInfo = runtimeInfo;
    }
    
}
